import type {
    RouteLocationNormalized,
    RouteRecordNormalized,
    RouteRecordRaw,
    Router,
} from 'vue-router'

import router from '@/router'
import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { getManRouters } from '@fl/api/man-api/authentication'
import { getRouters } from '@fl/api/purchase/role'
import { useUserStoreWithOut } from '@fl/store/modules/user'
import { isUrl } from '@fl/utils/is'
import { cloneDeep, omit } from 'lodash-es'
import { createRouter, createWebHashHistory } from 'vue-router'

// 根据角色设置路由
type IOptions = {
    isAdmin?: boolean
}

// 前端路由
export async function setRoutesByRoleByFrontend() {
    const userStore = useUserStoreWithOut()
    const permissionStore = usePermissionStoreWithOut()

    const userInfo = userStore.getUserInfo

    const { sysUser: { roles } } = userInfo as any

    const currentRole = roles?.[0]
    let roleRouters = [] as string[]

    if (currentRole) {
        const roleKey = currentRole.roleKey

        // 采购商
        if (roleKey === 'purchaser') {
            roleRouters = ['/purchase-pages']
        }
        // 供应商
        else if (roleKey === 'supplier') {
            roleRouters = ['/supplier-pages']
        }
        // 运营官
        else if (roleKey === 'operationer') {
            roleRouters = ['/operations-pages']
        }

        userStore.setRoleRouters(roleRouters)

        // 追加路由
        await permissionStore.generateRoutes('frontEnd', roleRouters as string[]).catch(() => {})
        permissionStore.getAddRouters.forEach((route) => {
            router.addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
        })
        permissionStore.setIsAddRouters(true)

        if (roleKey === 'operationer') {
            // 运营官进到后台页面去
            // 提前把分片路由切一刀, 免得侧边栏空白
            permissionStore.setSliceRouters('/operations-pages')
            router.push({ path: permissionStore.addRouters[0].path })
            return
        }
    }
    router.push('/')
}

export async function setRoutesByRole(options: IOptions = {}) {
    const { isAdmin = false } = options

    const userStore = useUserStoreWithOut()
    const permissionStore = usePermissionStoreWithOut()

    const fn = isAdmin ? getManRouters : getRouters
    const roleRouters = await fn()

    // 缓存后台请求
    userStore.setRoleRouters(roleRouters)

    // 拼装路由
    await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[], options).catch(() => {})
    permissionStore.getAddRouters.forEach((route) => {
        router.addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
    })

    // 存储切片路由; 可以根据角色写死
    const validPath = findFirstValidPath(permissionStore.addRouters)

    const pathPrefix = validPath.match(/^\/[^/]+/)?.[0]
    permissionStore.setSliceRouters(pathPrefix ?? '/')
    permissionStore.setIsAddRouters(true)

    // 每个角色登录后都应该进到首页
    router.push('/')
}

const modules = {
    ...import.meta.glob('../pages/**/*.{vue,tsx}'),
    ...import.meta.glob('../operations-pages/**/*.{vue,tsx}'),
    ...import.meta.glob('../purchase-pages/**/*.{vue,tsx}'),
    ...import.meta.glob('../supplier-pages/**/*.{vue,tsx}'),
}

/* Layout */
export const Layout = () => import('@/layout/layout.vue')

export function getParentLayout() {
    return () =>
        new Promise((resolve) => {
            resolve({
                name: 'ParentLayout',
            })
        })
}

export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized {
    if (!route)
        return route
    const { matched, ...opt } = route
    return {
        ...opt,
        matched: (matched
            ? matched.map(item => ({
                meta: item.meta,
                name: item.name,
                path: item.path,
            }))
            : undefined) as RouteRecordNormalized[],
    }
}

// 前端控制路由生成
export function generateRoutesByFrontEnd(routes: AppRouteRecordRaw[], keys: string[], basePath = '/'): AppRouteRecordRaw[] {
    const res: AppRouteRecordRaw[] = []

    for (const route of routes) {
        const meta = route.meta ?? {}
        // skip some route
        if (meta.hidden && !meta.canTo)
            continue

        let data: Nullable<AppRouteRecordRaw> = null

        let onlyOneChild: Nullable<string> = null
        if (route.children && route.children.length === 1 && !meta.alwaysShow) {
            onlyOneChild = (
                isUrl(route.children[0].path)
                    ? route.children[0].path
                    : pathResolve(pathResolve(basePath, route.path), route.children[0].path)
            ) as string
        }

        // 开发者可以根据实际情况进行扩展
        for (const item of keys) {
            // 通过路径去匹配
            if (isUrl(item) && (onlyOneChild === item || route.path === item)) {
                data = Object.assign({}, route)
            }
            else {
                const routePath = (onlyOneChild ?? pathResolve(basePath, route.path)).trim()
                if (routePath === item || meta.followRoute === item)
                    data = Object.assign({}, route)
            }
        }

        // ! 前端生成无需递归
        // recursive child routes
        // if (route.children && data) {
        //     data.children = generateRoutesByFrontEnd(
        //         route.children,
        //         keys,
        //         pathResolve(basePath, data.path),
        //     )
        // }
        if (data)
            res.push(data as AppRouteRecordRaw)
    }
    return res
}

// 后端控制路由生成
export function generateRoutesByServer(routes: AppCustomRouteRecordRaw[], options: IOptions = {}, prefixPath = ''): AppRouteRecordRaw[] {
    const { isAdmin = false } = options

    const res: AppRouteRecordRaw[] = []

    for (const route of routes) {
        const data: AppRouteRecordRaw = {
            component: Layout, // 若依框架 component 给的空, 直接写死
            meta: {
                activeMenu: route.meta?.activeMenu,
                alwaysShow: route?.alwaysShow ?? false,
                hidden: route.meta?.hidden,
                icon: route.meta?.icon,
                isAdmin, // 集采运营端会添加这个字段, 从而在页面复用组件时候能做出判断, 调用正确的接口
                noCache: route.meta?.noCache,
                noTagsView: route.meta?.hidden,
                permission: route.meta?.permission,
                title: route.meta?.title,
            },
            path: route.path!,
            redirect: route?.redirect === 'noRedirect' ? undefined : route.redirect,
        }
        if (route.component) {
            const comModule = modules[`../${route.component}.vue`] || modules[`../${route.component}.tsx`]
            const component = route.component as string

            if (comModule) {
                data.component = comModule
            }
            else {
                if (component === 'Layout') {
                    data.component = Layout
                }
                else if (component === 'ParentView') {
                    data.component = getParentLayout()
                }
                else {
                    console.error(`${JSON.stringify(route)}, 未找到${route.component}.vue文件, 请创建`)
                }
            }
        }

        // 修改 router 的 name, name 使用全路径
        const tmpPath = route.path?.startsWith('/') ? route.path : `${prefixPath}/${route.path}`
        data.name = tmpPath

        // recursive child routes
        if (route.children?.length) {
            data.children = generateRoutesByServer(route.children, options, tmpPath)
        }

        res.push(data as AppRouteRecordRaw)
    }
    return res
}

// 找寻可用路径
export function findFirstValidPath(routes: AppRouteRecordRaw[]) {
    function dfsPath(routes: AppRouteRecordRaw[], path: string) {
        const validRoutes = routes.filter(item => !item.meta.hidden)

        for (let i = 0; i < validRoutes.length; i++) {
            const route = validRoutes[i]

            path += route.path.startsWith('/') ? route.path : `/${route.path}`

            // 如果还存在子孙, 继续拼接
            if (route.children?.length) {
                return dfsPath(route.children, path)
            }

            if (path) {
                break
            }
        }

        return path
    }

    const validPath = dfsPath(routes, '')

    return validPath
}

export function pathResolve(parentPath: string, path: string) {
    if (isUrl(path))
        return path
    const childPath = path.startsWith('/') || !path ? path : `/${path}`
    return `${parentPath}${childPath}`.replace(/\/\//g, '/').trim()
}

// 路由降级
export function flatMultiLevelRoutes(routes: AppRouteRecordRaw[]) {
    const modules: AppRouteRecordRaw[] = cloneDeep(routes)
    for (let index = 0; index < modules.length; index++) {
        const route = modules[index]
        if (!isMultipleRoute(route))
            continue

        promoteRouteLevel(route)
    }
    return modules
}

// 层级是否大于2
function isMultipleRoute(route: AppRouteRecordRaw) {
    if (!route || !Reflect.has(route, 'children') || !route.children?.length)
        return false

    const children = route.children

    let flag = false
    for (let index = 0; index < children.length; index++) {
        const child = children[index]
        if (child.children?.length) {
            flag = true
            break
        }
    }
    return flag
}

// 生成二级路由
function promoteRouteLevel(route: AppRouteRecordRaw) {
    let router: Router | null = createRouter({
        history: createWebHashHistory(),
        routes: [route as RouteRecordRaw],
    })

    const routes = router.getRoutes()
    addToChildren(routes, route.children || [], route)
    router = null

    route.children = route.children?.map(item => omit(item, 'children'))
}

// 添加所有子菜单
function addToChildren(routes: RouteRecordNormalized[], children: AppRouteRecordRaw[], routeModule: AppRouteRecordRaw) {
    for (let index = 0; index < children.length; index++) {
        const child = children[index]
        const route = routes.find(item => item.name === child.name)
        if (!route)
            continue

        routeModule.children = routeModule.children || []
        if (!routeModule.children.find(item => item.name === route.name))
            routeModule.children?.push(route as unknown as AppRouteRecordRaw)

        if (child.children?.length)
            addToChildren(routes, child.children, routeModule)
    }
}
